#include "tNode.h"
#include <sstream>

tNode::tNode(SmartPointer<heuristicCalc>& nHCalc, SmartPointer<int>& nState, 
			 SmartPointer<tNode>& nFather, const int nLenTab , const int nTotalCout)
{
	father = nFather;
	state = nState;
	hCalc = nHCalc;
	lenTab = nLenTab;
	cout = 1;
	totalCout = nTotalCout;
	makeKey();
}

tNode::tNode(tNode& nNode)
{
	(*this) = nNode;
}

tNode::~tNode()
{}

const tNode&	tNode::operator=(tNode& nNode)
{
	H = nNode.getH();
	cout = nNode.getCout();
	state = nNode.getState();
	father = nNode.getFather();
	hCalc = nNode.getHCalc();
	key = nNode.getKey();
	return (*this);
}

const bool		tNode::operator==(tNode& oNode)
{
	int count;

	SmartPointer<int>& oState = oNode.getState();

	for (count = 0; state[count] && oState[count]; count++)
			if (state[count] != oState[count])
				return false;
	return true;
}

const int		tNode::getH() const
{
	return H;
}

const int		tNode::getCout() const
{
	return cout;
}

SmartPointer<tNode>&	tNode::getFather() 
{
	return father;
}

SmartPointer<int>&		tNode::getState()
{
	return state;
}

void	tNode::setFather(const SmartPointer<tNode>& nFather)
{
	father = nFather;
}

const bool	tNode::sortNode(tNode& fNode, tNode& sNode)
{
	if (fNode.getH() < sNode.getH())
		return true;
	return false;
}

const int					tNode::getTotalCout() const
{
	return totalCout;
}

SmartPointer<heuristicCalc>&	tNode::getHCalc()
{
	return hCalc;
}

void	tNode::makeSuiteNode(std::list<SmartPointer<tNode>>& lst, SmartPointer<tNode>& nFather)
{
	int					sCount, count, x, y, limit, posZ;
	int*				nTab;
	int					stop = lenTab * lenTab;

	if (state.getPointer())
	{
		posZ = 0;
		while (state[posZ] != 0 && posZ < stop)
			posZ++;
		 x = posZ % lenTab;
		 y = posZ / lenTab;
		 limit = LIMIT(x,y);
		 for (count = 0; count < limit; count++)
		 {
			nTab = new int[stop];
			for (sCount = 0; sCount < stop; sCount++)
				nTab[sCount] = state[sCount];
			if (count == 0)
			{
				if (y == 0 && x != lenTab - 1)
					moveRight(nTab, posZ);
				else if (y == 0)
					moveLeft(nTab, posZ);
				else
					moveUp(nTab, posZ);
			}
			else if (count == 1)
			{
				if (y == lenTab - 1 && x == lenTab - 1)
					moveLeft(nTab, posZ);
				else if (y == 0 || x == lenTab - 1)
					moveDown(nTab, posZ);
				else 
					moveRight(nTab, posZ);
			}
			else if (count == 2)
			{
				if (y == 0 || x == lenTab - 1 || y == lenTab - 1 )
					moveLeft(nTab, posZ);
				else
					moveDown(nTab, posZ);
			}
			else
				moveLeft(nTab, posZ);
			SmartPointer<int>	tab(nTab);
			lst.push_back(SmartPointer<tNode>( new tNode(hCalc, tab, nFather, lenTab, (totalCout + 1) )));
		}
	}
}

void	tNode::moveDown(int* tab, const int posZ)
{
	 char tmp;
	 int pos = (((posZ / lenTab) + 1) * lenTab) + (posZ % lenTab);
	 tmp  = tab[pos];
	 tab[pos] = 0;
	 tab[posZ] = tmp;
}

void	tNode::moveUp(int* tab, const int posZ)
{
	char tmp;
	int pos = (((posZ / lenTab) - 1) * lenTab) + (posZ % lenTab);
	
	tmp  = tab[pos];
	tab[pos] = 0;
	tab[posZ] = tmp;
}

void	tNode::moveLeft(int* tab, const int posZ)
{
	char tmp;
	
	tmp = tab[posZ - 1];
	tab[posZ - 1] = 0;
	tab[posZ] = tmp;
}

void	tNode::moveRight(int* tab, const int posZ)
{
		char tmp;

	tmp = tab[posZ + 1];
	tab[posZ + 1] = 0;
	tab[posZ] = tmp;
}

void	tNode::setTotalCout(const int nTotalCout)
{
	totalCout = nTotalCout;
}

void	tNode::launchCalc(int* finalState)
{
	H = hCalc.getPointer()->calcScore(state.getPointer(), finalState, lenTab);
	H += totalCout;
}

void	tNode::makeKey()
{
	std::stringstream st;
	int stop = lenTab * lenTab, count;

	for (count = 0; count < stop ;count++)
		st << state[count];
	key = st.str();
}

std::string&	tNode::getKey()
{
	return key;
}

const int	tNode::getLenTab() const
{
	return lenTab;
}

void	tNode::setH(const int nH)
{
	H = nH;
}

std::ostream&	operator <<(std::ostream& i, tNode& n)
{
	int		lenTab = n.getLenTab();
	int		stop = lenTab * lenTab;
	int		count;
	int*	state = n.getState().getPointer();

	for (count = 0; count < stop; count++)
	{
		if (count && (count % lenTab) == 0)
			i << std::endl;
		i << state[count] << ' ';
	}	
	i << std::endl;
	return i;
}